/**
 * $Author: francesco.benincasa $
 * $Date: 2007-03-08 13:07:20 +0100 (gio, 08 mar 2007) $
 * $Rev: 502 $
 */
package org.stars.database;


import java.util.Collection;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.stars.database.connectionpool.DisabledConnectionPool;
import org.stars.database.loader.xml.ConnectionsLoader;
import org.stars.util.FileUtility;
import org.stars.util.StringUtility;

/**
 * Carica la configurazione delle connessioni. I File di configurazione che
 * carica sono del tipo
 * 
 * <code><pre>
 *      &lt;![CDATA[
 *       &lt;?xml version=&quot;1.0&quot; encoding=&quot;ISO-8859-1&quot;?&gt;
 *       &lt;connections&gt;	
 *       &lt;connection-pool name=&quot;websecurity&quot; type=&quot;mixed-oracle-jndi&quot;&gt;
 *       &lt;jndi&gt;java:/comp/env/jdbc/websecurity&lt;/jndi&gt;
 *       	&lt;url&gt;jdbc:oracle:thin:@172.22.8.28:1522:B&lt;/url&gt; 
 *       &lt;user&gt;M01&lt;/user&gt;
 *       &lt;pwd&gt;M01&lt;/pwd&gt;
 *       &lt;/connection-pool&gt;
 *       &lt;/connections&gt;
 *       ]]&gt;
 * </pre></code>
 * 
 * @author Francesco Benincasa (908099)
 * 
 */
public class DatabaseConfigurator {
	/**
	 * SingletonHolder is loaded on the first execution of
	 * Singleton.getInstance() or the first access to SingletonHolder.INSTANCE,
	 * not before.
	 */
	private static class DatabaseConfiguratorHolder {
		public static final DatabaseConfigurator INSTANCE = new DatabaseConfigurator();
	}

	public static DatabaseConfigurator getInstance() {
		return DatabaseConfiguratorHolder.INSTANCE;
	}
	/**
	 * connessione di default
	 */
	private String defaultConnectionName;

	/**
	 * costruttore. Imposta la configurazione di default.
	 */
	private DatabaseConfigurator() {	
	}

	/**
	 * getter del default connection name
	 * 
	 * @return nome della connessione
	 */
	public String getDefaultConnectionName() {
		return defaultConnectionName;
	}

	/**
	 * Logger
	 * 
	 * @return
	 * 		logger
	 */
	protected static Log getLog()
	{
		return LogFactory.getLog(ConnectionPoolManager.class);
	}

	/**
	 * A partire dal percorso specificato, carica la configurazione dei vari
	 * connection pool. Il file di configurazione si deve trovare sotto la
	 * sottocartella websecurity e deve avere il nome connections.xml. Il path
	 * deve finire con il carattere di separazione.
	 * 
	 * Il connection pool di default viene preso automaticamente. Nel caso ce ne
	 * sia solo uno viene preso quello, nel caso ce ne siano più di uno viene
	 * preso il primo ma viene segnalato che la scelta è stata presa in modo
	 * autonomo.
	 * 
	 * @param configFile
	 * @return <code>true</code> se la configurazione è andata a buon fine
	 * @throws Exception
	 */
	public boolean loadConfigurationFromFile(String configFile) throws Exception {
		// iniziamo il conto del tempo impiegato per caricare la configurazione
		long time=System.currentTimeMillis();
		
		// carica la configurazione da file
		boolean bRet = loadXmlFiles(configFile);		
		//	numero di connection pool presenti
		int numCp = 0; 
		Log log = getLog();
		// valore
		boolean bExistDefaultConnection = false;

		ConnectionPoolManager cpm = ConnectionPoolManager.getInstance();
		String sDefaultConnectionName = StringUtility.nvl(cpm
				.getDefaultConnectionName());

		// se esiste la connessione di default siamo ok.
		if (cpm.getConnectionPool(sDefaultConnectionName)!=null)
		{
			bExistDefaultConnection = true;			
		}		

		numCp = cpm.getAllConnectionPool().size();

		// vediamo se ci sono connessioni
		if (numCp == 0) {
			String error = "No connection definition found in the config file "+configFile;			
			log.fatal(error);
			throw (new DatabaseException(error));
		}

		if (sDefaultConnectionName.length() > 0 && bExistDefaultConnection) {
			// ASSERT: il connection pool di default esiste
			String info = cpm.getDefaultConnectionName()
					+ " impostato come connection pool di default.";
			log.info(info);
		} else {
			String warn = "";
			if (numCp > 1) {
				warn = "Sono presenti diversi connection pool e non si e' definito esplicitamente quale utilizzare come default.";
				log.warn(warn);
			}

			Collection<ConnectionPool> e = cpm.getAllConnectionPool().values();

			// prendiamo il primo disponibile
			for(ConnectionPool item: e)
			{
				ConnectionPool cp = item;
				
				if (!(cp instanceof DisabledConnectionPool))
				{
					String defaultName = cp.getName();

					cpm.setDefaultConnectionName(defaultName);

					warn = defaultName
						+ " impostato come connection pool di default.";
					log.info(warn);
					break;
				}
			}
			
			if (cpm.getDefaultConnectionPool() == null)
			{
				String error = "Il connection pool "
						+ sDefaultConnectionName
						+ " non esiste. Impossibile determinare il connection pool di default";
				
				log.fatal("DatabaseStar Initialization FAILED. Version "
						+ DatabaseConfigurator.getVersion() + " IS NOT loaded.");
				throw (new DatabaseException(error));
			}
		}
		
		time=System.currentTimeMillis()-time;
		log.info("DatabaseStar Initialization Complete. Version "
				+ DatabaseConfigurator.getVersion() + " is loaded in "+time+" ms.");

		return bRet;
	}
	
	/**
	 * Restituisce il numero di versione
	 * @return
	 * 		stringa che contiene la versione della libreria
	 */
	public static String getVersion()
	{
		return "1.0.0";
	}

	/**
	 * A partire dal percorso specificato, carica la configurazione dei vari
	 * connection pool. Il file di configurazione si deve trovare sotto la
	 * sottocartella websecurity e deve avere il nome connections.xml. Il path
	 * deve finire con il carattere di separazione.
	 * 
	 * @param sPath
	 *            percorso assoluto dal quale cercare il file di configurazione.
	 * 
	 * Per costruire il nome del file corretto si consiglia di utilizzare al
	 * posto dei caratteri / o \ il separatore <code>File.separator</code>.
	 * 
	 * @param sPath
	 *            path dal quale applicare il percorso relativo
	 * 
	 * @return <code>true</code> se la configurazione è andata a buon fine.
	 */
	private boolean loadXmlFiles(String configFile) {
		Log log = getLog();
		// ----------------------------------------------------------------------
		// Recuperiamo le connessioni al database inserite nel file
		// connections.xml
		// ----------------------------------------------------------------------
		String sFile = "";
		try {			
			ConnectionsLoader loader = new ConnectionsLoader();

			sFile = FileUtility.adjustPath(configFile);
			log.info("Configurazione jar insiel-database letta dal file  "
					+ sFile);
			loader.load(sFile);

		} catch (Exception e) {			
			log.error("Riscontrato errore durante il caricamento del file "
					+ sFile + ": " + e.toString());
			log.error("----------------------------------------------------");
		}
		return true;
	}


	/**
	 * @param defaultConnectionName
	 */
	public void setDefaultConnectionName(String defaultConnectionName) {
		this.defaultConnectionName = defaultConnectionName;
	}


}
